/*
 * ReimsCopieUserBean.java
 *
 * Created on 13 novembre 2007, 16:54
 */
package com.reimscopie.beans.session;

import java.util.* ;

import javax.ejb.* ;
import javax.naming.* ;
import javax.persistence.* ;

import com.reimscopie.* ;
import com.reimscopie.beans.entities.* ;
import com.reimscopie.beans.interfaces.* ;


/**
 * This stateful is the basic user bean. The user session is managed in this
 * bean.
 */
@Stateful
@Local(ReimsCopieUserLocal.class)
@Remote(ReimsCopieUserRemote.class)
public class ReimsCopieUserBean extends ReimsCopieAccessBean {
  
  // persistence
  @PersistenceContext()
  private EntityManager entityManager ;
  
  // the cart with selected products
  private Cart cart;
  
  // account if we have a logged session
  private AccountBean account ;
  
  
  /**
   * Create a new <code>ReimsCopieUserBean</code> instance.
   * This constructor creates a new cart.
   */
  public ReimsCopieUserBean() {
        
    cart = new Cart() ;
    
  }
  
  
  /**
   * Return this persistence manager used by this bean.
   *
   * @return The persistence manager to use.
   */
  @Override
  protected EntityManager getPersistenceManager() {
    return entityManager ;
  }
  
  
////////////////////////////////////////////////////////////////////////////////
//                               LOGIN                                        //
////////////////////////////////////////////////////////////////////////////////
  
  /**
   * Open the session. The user has to give a login and a password.
   *
   * <p>The session is not opened is the login and password are not correct.
   * In this case, this method returns <code>false</code>.
   *
   * @param login The user login.
   * @param password The user password.
   *
   * @return <code>true</code> if the session is successfuly opened,
   * <code>false</code> otherwise.
   */
  public boolean login(String login,String password) {
    
    AccountBean bean = (AccountBean)executeSingleQuery(entityManager,
        "get-login",login) ;
    
    // account not found
    if (bean == null)
      return false ;
    
    // wrong password
    String beanPassword = bean.getPassword() ;
    if (!beanPassword.equals(password))
      return false ;
    
    // success
    this.account = bean ;
    
    return true ;
    
  }
  
  
  /**
   * Log out from the session.
   */
  public void logout() {
    
    account = null ;
    
  }
  
  
  /**
   * Return is the user session has a logged account.
   *
   * @return <code>true</code> if the session is logged, <code>false</code>
   * otherwise.
   */
  public boolean isLogged() {
    return account != null ;
  }
  
  
  /**
   * Return the user account.
   *
   * @return The user account, or <code>null</code> is the user is not logger
   * in.
   */
  public Account getUserAccount() {
    
    if (account == null)
      return null ;
    else
      return account.toAccount() ;
    
  }
  
  
  /**
   * Update a user account. The user has to give a account.
   *
   * @param The new account values.
   */
  public void updateUserAccount(Account a) {
    
    if (!isLogged())
      throw new IllegalStateException("not logged in") ;
    
    // account
    account.setMail(a.getMail()) ;
    account.setNewsLetter(a.getNewsLetter()) ;
    if (a.getPassword() != null)
      account.setPassword(a.getPassword()) ;
    
    // perso
    PersonalInfo info = a.getPersonalInfo() ;
    account.getPersonalInfo().setName(info.getName()) ;
    account.getPersonalInfo().setFirstName(info.getFirstName()) ;
    account.getPersonalInfo().setStreet(info.getStreet()) ;
    account.getPersonalInfo().setPostalCode(info.getPostalCode()) ;
    account.getPersonalInfo().setCity(info.getPostalCode()) ;
    account.getPersonalInfo().setCountry(info.getCountry()) ;
    account.getPersonalInfo().setPhone(info.getPhone()) ;
    
    entityManager.merge(account.getPersonalInfo()) ;
    entityManager.merge(account) ;
  }
  
  
////////////////////////////////////////////////////////////////////////////////
//                              CART                                          //
////////////////////////////////////////////////////////////////////////////////
  
  /**
   * Add a new purchase in the cart.
   *
   * @param purchase The purchase to add in the user's cart.
   */
  public void addPurchase(Purchase purchase) {
    
    cart.addPurchase(purchase) ;
    
  }
  
  
  /**
   * Return all pruchase form the cart.
   *
   * @return All purchases.
   */
  public Purchase[] getCart() {
    return cart.getPurchases() ;
  }
  
  
  /**
   * Return the total price of the current cart.
   *
   * @return The total price of the current user's cart.
   */
  public float getCartPrice() {
    
    return cart.getTotalCost() ;
        
  }
  
  
  /**
   * Order the cart for the current user's cart.
   * The cart is emptied by the CartBean and transform to an
   * Order, put in persistence.
   *
   * @return <code>true</code> if the ordre is successfully created,
   * <code>false</code> instead.
   */
  public boolean orderCart() {
    
    float currentBalance = account.getBalance() ;
    float cartPrice      = cart.getTotalCost() ;
    boolean stockOk = true ;
    
    if(currentBalance < cartPrice)
      return false ;
    
    Order order = cart.toOrder() ;
    ProductBean[] products = new ProductBean[order.getPurchases().length] ;
    
    // product beans
    for (int i=0;i<products.length;i++) {
      Purchase purchase = order.getPurchases()[i] ;
      long id = purchase.getProduct().getId() ;
      products[i] = entityManager.find(ProductBean.class,id) ;
      if     (products[i] instanceof SimpleProductBean
          && (((SimpleProductBean) products[i]).getStock()<purchase.getQuantity()))
        stockOk = false ;
      else if(products[i] instanceof SpecialProductBean
          && (((SpecialProductBean)products[i]).getStock()<purchase.getQuantity()))
        stockOk = false ;
    }
    
    // not enough stock
    if (!stockOk)
      return false ;
    
    OrderBean orderBean = new OrderBean(order,products) ;
    
    // persistence
    for (PurchaseBean purchase : orderBean.getPurchases())
      entityManager.persist(purchase) ;
    entityManager.persist(orderBean) ;
    
    // decrement stock
    for (int i=0;i<products.length;i++) {
      Purchase purchase = order.getPurchases()[i] ;
      if(products[i] instanceof SimpleProductBean)
         ((SimpleProductBean)products[i]).setStock(((SimpleProductBean)products[i]).getStock() - purchase.getQuantity()) ;
      else if(products[i] instanceof SpecialProductBean)
         ((SpecialProductBean)products[i]).setStock(((SpecialProductBean)products[i]).getStock() - purchase.getQuantity()) ;
      entityManager.merge(products[i]) ;
    }
    
    // success
    cart.empty() ;
    account.setBalance(currentBalance - cartPrice) ;
    entityManager.merge(account) ;
    return true ;
  }
  
  
  /**
   * Remove all products from the cart.
   */
  public void emptyCart() {
    
    cart.empty() ;
    
  }
  
  
////////////////////////////////////////////////////////////////////////////////
//                              PRODUCTS                                      //
////////////////////////////////////////////////////////////////////////////////
  
  /**
   * Search for available products in the database.
   *
   * @param expr The expression to search.
   *
   * @return The identifiers of the found products.
   */
  public long[] search(String expr) {
    
    StringBuilder builder = new StringBuilder() ;
    builder.append('%') ;
    builder.append(expr) ;
    builder.append('%') ;
    expr = builder.toString() ;
    
    Object[] objects = executeMultipleQuery(entityManager,"search-product",expr) ;
    
    long[] ids = new long[objects.length] ;
    for (int i=0;i<ids.length;i++)
      ids[i] = ((Long)objects[i]).longValue() ;
    
    return ids ;
    
  }
  
}
